﻿using System.Collections;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;

namespace Koala.Pro.Controls
{
    public partial class TreeComboBox : UserControl
    {
        public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(TreeComboBox), new PropertyMetadata(null, OnSelectedItem_Changed));

        public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(TreeComboBox), new PropertyMetadata(null, OnItemsSource_Changed));

        public static readonly DependencyProperty DisplayPathProperty = DependencyProperty.Register("DisplayPath", typeof(string), typeof(TreeComboBox), new PropertyMetadata("", OnDisplayPath_Changed));

        public static readonly DependencyProperty TreeItemStyleProperty = DependencyProperty.Register("TreeItemStyle", typeof(Style), typeof(TreeComboBox), new PropertyMetadata(null, OnTreeItemStyle_Changed));

        public static readonly DependencyProperty TreeItemItemTemplateProperty = DependencyProperty.Register("TreeItemItemTemplate", typeof(HierarchicalDataTemplate), typeof(TreeComboBox), new PropertyMetadata(null, OnTreeItemItemTemplate_Changed));

        private TreeView DropDownTreeViewer;

        public static readonly RoutedEvent SelectedItemChangedEvent;

        public static readonly DependencyProperty TreeViewItemClickCommandProperty;

        public static readonly DependencyProperty TreeViewItemClickCommandParameterProperty;

        public static readonly DependencyProperty TreeViewItemClickTargetProperty;

        public static readonly DependencyProperty TextProperty;

        public object SelectedItem
        {
            get
            {
                return GetValue(SelectedItemProperty);
            }
            set
            {
                SetValue(SelectedItemProperty, value);
            }
        }

        public IEnumerable ItemsSource
        {
            get
            {
                return (IEnumerable)GetValue(ItemsSourceProperty);
            }
            set
            {
                SetValue(ItemsSourceProperty, value);
            }
        }

        public string DisplayPath
        {
            get
            {
                return (string)GetValue(DisplayPathProperty);
            }
            set
            {
                SetValue(DisplayPathProperty, value);
            }
        }

        public Style TreeItemStyle
        {
            get
            {
                return (Style)GetValue(TreeItemStyleProperty);
            }
            set
            {
                SetValue(TreeItemStyleProperty, value);
            }
        }

        public HierarchicalDataTemplate TreeItemItemTemplate
        {
            get
            {
                return (HierarchicalDataTemplate)GetValue(TreeItemItemTemplateProperty);
            }
            set
            {
                SetValue(TreeItemItemTemplateProperty, value);
            }
        }

        public ICommand TreeViewItemClickCommand
        {
            get
            {
                return (ICommand)GetValue(TreeViewItemClickCommandProperty);
            }
            set
            {
                SetValue(TreeViewItemClickCommandProperty, value);
            }
        }

        public object TreeViewItemClickCommandParameter
        {
            get
            {
                return GetValue(TreeViewItemClickCommandParameterProperty);
            }
            set
            {
                SetValue(TreeViewItemClickCommandParameterProperty, value);
            }
        }

        public IInputElement TreeViewItemClickTarget
        {
            get
            {
                return (IInputElement)GetValue(TreeViewItemClickTargetProperty);
            }
            set
            {
                SetValue(TreeViewItemClickTargetProperty, value);
            }
        }

        public string Text
        {
            get
            {
                return (string)GetValue(TextProperty);
            }
            set
            {
                SetValue(TextProperty, value);
            }
        }

        public event RoutedEventHandler SelectedItemChanged
        {
            add
            {
                AddHandler(SelectedItemChangedEvent, value);
            }
            remove
            {
                RemoveHandler(SelectedItemChangedEvent, value);
            }
        }

        public TreeComboBox()
        {
            InitializeComponent();
            base.Loaded += OnThis_Loaded;
            EventManager.RegisterClassHandler(typeof(TreeView), TreeView.SelectedItemChangedEvent, new RoutedPropertyChangedEventHandler<object>(OnTreeView_SelectedItemChanged));
            EventManager.RegisterClassHandler(typeof(TreeViewItem), TreeViewItem.MouseLeftButtonUpEvent, new MouseButtonEventHandler(OnTreeViewItem_MouseUp));
            EventManager.RegisterClassHandler(typeof(TreeViewItem), TreeViewItem.MouseLeftButtonDownEvent, new MouseButtonEventHandler(OnTreeViewItem_MouseDown));

            ComboBox.DropDownOpened += OnComboBox_DropDownOpened;
        }

        private void OnTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            if (sender as TreeView != DropDownTreeViewer)
            {
                return;
            }
            if (e.NewValue != null)
            {
                SelectedItem = e.NewValue;
                SetDisplayText(e.NewValue);
            }
            new Thread((ThreadStart)delegate
            {
                Thread.Sleep(50);
                base.Dispatcher.BeginInvoke((Action)delegate
                {
                    ComboBox.IsDropDownOpen = false;
                });
            }).Start();
        }

        private void OnTreeViewItem_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (!(sender is TreeViewItem treeViewItem))
            {
                return;
            }
            object obj = TreeViewItemClickCommandParameter;
            if (obj == null)
            {
                obj = treeViewItem.DataContext;
            }
            TreeView treeView = FindVisualParent<TreeView>(treeViewItem);
            if (treeView != null && treeView == DropDownTreeViewer)
            {
                if (TreeViewItemClickCommand is RoutedCommand routedCommand)
                {
                    routedCommand.Execute(obj, TreeViewItemClickTarget);
                }
                else if (TreeViewItemClickCommand != null)
                {
                    TreeViewItemClickCommand.Execute(obj);
                }
            }
        }

        private void OnTreeViewItem_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (ComboBox.IsDropDownOpen)
            {
                ComboBox.IsDropDownOpen = false;
            }
        }

        public static T FindVisualParent<T>(DependencyObject obj) where T : DependencyObject
        {
            if (obj == null)
            {
                return null;
            }
            DependencyObject parent;
            for (parent = VisualTreeHelper.GetParent(obj); parent != null; parent = VisualTreeHelper.GetParent(parent))
            {
                if (parent is T)
                {
                    return parent as T;
                }
            }
            return parent as T;
        }

        private void OnComboBox_DropDownOpened(object sender, EventArgs e)
        {
            if (DropDownTreeViewer != null && SelectedItem != null && DropDownTreeViewer.SelectedValue != SelectedItem)
            {
                SetTreeViewSelectedItem(SelectedItem);
            }
        }

        private void SetDisplayText(object item)
        {
            if (item == null)
            {
                ComboBox.Items.Clear();
                ComboBox.Text = "";
                return;
            }
            if (!string.IsNullOrEmpty(DisplayPath))
            {
                string[] array = DisplayPath.Split('.');
                if (array.Length != 0)
                {
                    object obj = item;
                    for (int i = 0; i < array.Length; i++)
                    {
                        PropertyInfo property = obj.GetType().GetProperty(array[i], BindingFlags.Instance | BindingFlags.Public);
                        if (property != null)
                        {
                            obj = property.GetValue(obj);
                        }
                        if (obj == null || i == array.Length - 1)
                        {
                            ComboBox.Items.Clear();
                            string text = (obj ?? "NaN??").ToString();
                            ComboBox.Items.Add(text);
                            ComboBox.Text = text;
                            return;
                        }
                    }
                }
            }
            ComboBox.Items.Clear();
            ComboBox.Items.Add(SelectedItem.ToString());
            ComboBox.Text = ComboBox.Items[0].ToString();
        }

        private static void OnSelectedItem_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TreeComboBox treeComboBox = d as TreeComboBox;
            if (treeComboBox != null && treeComboBox.DropDownTreeViewer != null)
            {
                treeComboBox.SetDisplayText(e.NewValue);
            }
            if (treeComboBox != null && e.NewValue != e.OldValue)
            {
                RoutedEventArgs e2 = new RoutedEventArgs(SelectedItemChangedEvent);
                treeComboBox.RaiseEvent(e2);
            }
        }

        private void SetTreeViewSelectedItem(object selectedValue)
        {
            if (selectedValue == null || DropDownTreeViewer == null)
            {
                return;
            }
            if (DropDownTreeViewer.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
            {
                SelectedTheTreeViewItem(selectedValue);
                return;
            }
            EventHandler[] eventHandler = new EventHandler[1];
            eventHandler[0] = delegate
            {
                if (DropDownTreeViewer.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
                {
                    DropDownTreeViewer.ItemContainerGenerator.StatusChanged -= eventHandler[0];
                    SelectedTheTreeViewItem(selectedValue);
                }
            };
            DropDownTreeViewer.ItemContainerGenerator.StatusChanged += eventHandler[0];
        }

        private void SelectedTheTreeViewItem(object selectedValue)
        {
            for (int i = 0; i < DropDownTreeViewer.ItemContainerGenerator.Items.Count; i++)
            {
                if (DropDownTreeViewer.ItemContainerGenerator.ContainerFromIndex(i) is TreeViewItem treeViewItem)
                {
                    if (DropDownTreeViewer.ItemContainerGenerator.ItemFromContainer(treeViewItem) == selectedValue)
                    {
                        treeViewItem.IsSelected = true;
                        TunThreadSetIsOpen();
                        break;
                    }
                    SetTreeViewItemSelected(treeViewItem, selectedValue);
                }
            }
        }

        private void TunThreadSetIsOpen()
        {
            new Thread((ThreadStart)delegate
            {
                Thread.Sleep(100);
                base.Dispatcher.Invoke(delegate
                {
                    if (!ComboBox.IsDropDownOpen)
                    {
                        ComboBox.IsDropDownOpen = true;
                    }
                });
            }).Start();
        }

        private void SetTreeViewItemSelected(TreeViewItem treeViewItem, object selectedValue)
        {
            if (treeViewItem == null || selectedValue == null)
            {
                return;
            }
            if (treeViewItem.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
            {
                for (int i = 0; i < treeViewItem.ItemContainerGenerator.Items.Count; i++)
                {
                    if (treeViewItem.ItemContainerGenerator.ContainerFromIndex(i) is TreeViewItem treeViewItem2)
                    {
                        if (treeViewItem.ItemContainerGenerator.ItemFromContainer(treeViewItem2) == selectedValue)
                        {
                            treeViewItem2.IsSelected = true;
                            TunThreadSetIsOpen();
                            break;
                        }
                        SetTreeViewItemSelected(treeViewItem2, selectedValue);
                    }
                }
                return;
            }
            EventHandler[] eventHandler = new EventHandler[1];
            eventHandler[0] = delegate
            {
                if (treeViewItem.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
                {
                    treeViewItem.ItemContainerGenerator.StatusChanged -= eventHandler[0];
                    SetTreeViewItemSelected(treeViewItem, selectedValue);
                }
            };
            treeViewItem.ItemContainerGenerator.StatusChanged += eventHandler[0];
        }

        private static void OnItemsSource_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is TreeComboBox { DropDownTreeViewer: not null } treeComboBox)
            {
                treeComboBox.DropDownTreeViewer.ItemsSource = e.NewValue as IEnumerable;
            }
        }

        private static void OnDisplayPath_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is TreeComboBox treeComboBox)
            {
                treeComboBox.SetDisplayText(treeComboBox.SelectedItem);
            }
        }

        private static void OnTreeItemStyle_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is TreeComboBox { DropDownTreeViewer: not null } treeComboBox)
            {
                treeComboBox.DropDownTreeViewer.ItemContainerStyle = e.NewValue as Style;
            }
        }

        private static void OnTreeItemItemTemplate_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is TreeComboBox { DropDownTreeViewer: not null } treeComboBox)
            {
                treeComboBox.DropDownTreeViewer.ItemTemplate = e.NewValue as HierarchicalDataTemplate;
            }
        }

        private void OnThis_Loaded(object sender, RoutedEventArgs e)
        {
            if (DropDownTreeViewer == null)
            {
                DropDownTreeViewer = ComboBox.Template.FindName("InnerTreeView", ComboBox) as TreeView;
                if (DropDownTreeViewer != null)
                {
                    if (DropDownTreeViewer.ItemTemplate != TreeItemItemTemplate)
                    {
                        DropDownTreeViewer.ItemTemplate = TreeItemItemTemplate;
                    }
                    if (DropDownTreeViewer.ItemsSource != ItemsSource)
                    {
                        DropDownTreeViewer.Items.Clear();
                        DropDownTreeViewer.ItemsSource = ItemsSource;
                    }
                    if (DropDownTreeViewer.ItemContainerStyle != TreeItemStyle)
                    {
                        DropDownTreeViewer.ItemContainerStyle = TreeItemStyle;
                    }
                }
            }
            if (SelectedItem != null && string.IsNullOrEmpty(ComboBox.Text))
            {
                SetDisplayText(SelectedItem);
            }
            else if (SelectedItem == null)
            {
                SetDisplayText(null);
            }
        }

        static TreeComboBox()
        {
            SelectedItemChangedEvent = EventManager.RegisterRoutedEvent("SelectedItemChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TreeComboBox));
            TreeViewItemClickCommandProperty = DependencyProperty.Register("TreeViewItemClickCommand", typeof(ICommand), typeof(TreeComboBox), new PropertyMetadata(null));
            TreeViewItemClickCommandParameterProperty = DependencyProperty.Register("TreeViewItemClickCommandParameter", typeof(object), typeof(TreeComboBox), new PropertyMetadata(null));
            TreeViewItemClickTargetProperty = DependencyProperty.Register("TreeViewItemClickTarget", typeof(IInputElement), typeof(TreeComboBox), new PropertyMetadata(null));
            TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(TreeComboBox), new FrameworkPropertyMetadata("文本说明", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
        }
    }
}
